#pragma once

#include <assert.h>

#include "record/bitmap.h"
#include "multi_version_defs.h"
#include "multi_version_file_handle.h"

/* 记录管理器，用于管理表的数据文件，进行文件的创建、打开、删除、关闭 */
class MultiVersionManager {
   private:
    DiskManager *disk_manager_;
    BufferPoolManager *buffer_pool_manager_;

   public:
    MultiVersionManager(DiskManager *disk_manager, BufferPoolManager *buffer_pool_manager)
        : disk_manager_(disk_manager), buffer_pool_manager_(buffer_pool_manager) {}

    /**
     * @description: 创建表的数据文件并初始化相关信息
     * @param {string&} filename 要创建的表名称
     * @param {int} record_size 表中记录的大小
     */ 
    void create_file(const std::string& tab_name, int record_size) {
        if (record_size < 1 || record_size > MULTI_MAX_RECORD_SIZE) {
            throw InvalidRecordSizeError(record_size);
        }
        disk_manager_->create_file(tab_name + ".old");
        int fd = disk_manager_->open_file(tab_name + ".old");

        // 初始化file header
        MultiVersionFileHdr file_hdr{};
        file_hdr.record_size = record_size;
        file_hdr.num_pages = 1;
        file_hdr.first_free_page_no = MULTI_NO_PAGE;
        // We have: sizeof(hdr) + (n + 7) / 8 + n * record_size <= PAGE_SIZE
        file_hdr.num_records_per_page =
            (BITMAP_WIDTH * (PAGE_SIZE - 1 - (int)sizeof(MultiVersionFileHdr)) + 1) / (1 + record_size * BITMAP_WIDTH);
        file_hdr.bitmap_size = (file_hdr.num_records_per_page + BITMAP_WIDTH - 1) / BITMAP_WIDTH;

        // 将file header写入磁盘文件（名为file name，文件描述符为fd）中的第0页
        // head page直接写入磁盘，没有经过缓冲区的NewPage，那么也就不需要FlushPage
        disk_manager_->write_page(fd, MULTI_FILE_HDR_PAGE, (char *)&file_hdr, sizeof(file_hdr));
        disk_manager_->close_file(fd);
    }

    /**
     * @description: 删除表的数据文件
     * @param {string&} filename 要删除的文件名称
     */    
    void destroy_file(const std::string& filename) { disk_manager_->destroy_file(filename); }

    // 注意这里打开文件，创建并返回了record file handle的指针
    /**
     * @description: 打开表的数据文件，并返回文件句柄
     * @param {string&} filename 要打开的文件名称
     * @return {unique_ptr<MultiVersionFileHandle>} 文件句柄的指针
     */
    std::unique_ptr<MultiVersionFileHandle> open_file(const std::string& tab_name) {
        int fd = disk_manager_->open_file(tab_name + ".old");
        return std::make_unique<MultiVersionFileHandle>(disk_manager_, buffer_pool_manager_, fd);
    }
    /**
     * @description: 关闭表的数据文件
     * @param {MultiVersionFileHandle*} file_handle 要关闭文件的句柄
     */
    void close_file(const MultiVersionFileHandle* file_handle) {
        disk_manager_->write_page(file_handle->fd_, MULTI_FILE_HDR_PAGE, (char *)&file_handle->file_hdr_,
                                  sizeof(file_handle->file_hdr_));
        // 缓冲区的所有页刷到磁盘，注意这句话必须写在close_file前面
        buffer_pool_manager_->flush_all_pages(file_handle->fd_);
        disk_manager_->close_file(file_handle->fd_);
    }
};
